package org.ehe.common.log.aspect;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.StopWatch;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.ehe.common.core.domain.model.LoginUser;
import org.ehe.common.core.utils.ServletUtils;
import org.ehe.common.core.utils.SpringUtils;
import org.ehe.common.json.utils.JsonUtils;
import org.ehe.common.log.annotation.Log;
import org.ehe.common.log.enums.BusinessStatus;
import org.ehe.common.log.event.OperLogEvent;
import org.ehe.common.satoken.utils.LoginHelper;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.http.HttpMethod;
import org.springframework.validation.BindingResult;
import org.springframework.web.multipart.MultipartFile;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 操作日志记录处理
 *
 * @author zhangnn
 */
@Slf4j
@Aspect
@AutoConfiguration
public class LogAspect {

    /**
     * 排除敏感属性字段
     */
    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };


    /**
     * 计时 key
     */
    private static final ThreadLocal<StopWatch> KEY_CACHE = new ThreadLocal<>();
    /**
     * 业务类型与详情页URL的映射配置
     */
    private static final Map<String, String> BUSINESS_URL_MAPPING = new HashMap<>();

    static {
        // 配置各种业务类型的详情页URL模板
        BUSINESS_URL_MAPPING.put("engineer", "/engineer/detail/{id}");
        BUSINESS_URL_MAPPING.put("project", "/project/detail/{id}");
        BUSINESS_URL_MAPPING.put("task", "/task/detail/{id}");
        BUSINESS_URL_MAPPING.put("approval", "/workflow/approval/detail/{id}");
        BUSINESS_URL_MAPPING.put("user", "/system/user/detail/{id}");
        BUSINESS_URL_MAPPING.put("role", "/system/role/detail/{id}");
        BUSINESS_URL_MAPPING.put("drawing", "/drawing/detail/{id}");
        BUSINESS_URL_MAPPING.put("purchaseOrder", "/erp/purchase/createChildOrder/detail/{id}");

        // 可以根据业务需要继续添加...

    }

    /**
     * 处理请求前执行
     */
    @Before(value = "@annotation(controllerLog)")
    public void doBefore(JoinPoint joinPoint, Log controllerLog) {
        StopWatch stopWatch = new StopWatch();
        KEY_CACHE.set(stopWatch);
        stopWatch.start();
    }

    /**
     * 处理完请求后执行
     *
     * @param joinPoint 切点
     */
    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult) {
        handleLog(joinPoint, controllerLog, null, jsonResult);
    }

    /**
     * 拦截异常操作
     *
     * @param joinPoint 切点
     * @param e         异常
     */
    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e) {
        handleLog(joinPoint, controllerLog, e, null);
    }

    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult) {
        try {

            // *========数据库日志=========*//
            OperLogEvent operLog = new OperLogEvent();
            operLog.setTenantId(LoginHelper.getTenantId());
            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
            // 请求的地址
            String ip = ServletUtils.getClientIP();
            operLog.setOperIp(ip);
            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
            LoginUser loginUser = LoginHelper.getLoginUser();
            operLog.setOperName(loginUser.getUsername());
            operLog.setDeptName(loginUser.getDeptName());

            if (e != null) {
                operLog.setStatus(BusinessStatus.FAIL.ordinal());
                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 3800));
            }
            // 设置方法名称
            String className = joinPoint.getTarget().getClass().getName();
            String methodName = joinPoint.getSignature().getName();
            operLog.setMethod(className + "." + methodName + "()");
            // 设置请求方式
            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
            // 处理设置注解上的参数
            getControllerMethodDescription(joinPoint, controllerLog, operLog, jsonResult);
            // 设置消耗时间
            StopWatch stopWatch = KEY_CACHE.get();
            stopWatch.stop();
            operLog.setCostTime(stopWatch.getDuration().toMillis());
            // 【新增】拼接业务操作日志
            String bizLog = buildBizLogWithLink(controllerLog, joinPoint, e, jsonResult);
            operLog.setBizContent(bizLog);
            // 发布事件保存数据库
            SpringUtils.context().publishEvent(operLog);
        } catch (Exception exp) {
            // 记录本地异常日志
            log.error("异常信息:{}", exp.getMessage());
        } finally {
            KEY_CACHE.remove();
        }
    }

    /**
     * 构建业务操作日志内容（带超链接）
     */
    private String buildBizLogWithLink(Log controllerLog, JoinPoint joinPoint, Exception e, Object jsonResult) {
        // 1. 基础描述：优先用 @Log.operDesc，无则用 @Log.title
        String baseDesc = StringUtils.isNotBlank(controllerLog.operDesc())
            ? controllerLog.operDesc()
            : controllerLog.title();

        // 2. 拼接操作结果（成功/失败）
        String result = e != null ? "失败" : "成功";

        // 3. 提取关键参数和ID信息
        BizLogInfo bizInfo = extractBizInfo(joinPoint.getArgs(), jsonResult, controllerLog);

        // 4. 构建带超链接的业务描述
        String linkedDesc = buildLinkedDescription(baseDesc, bizInfo, result,controllerLog);

        return linkedDesc;
    }

    /**
     * 提取关键业务参数（例：从复杂参数中拿“name”“id”等核心字段）
     */
    private BizLogInfo extractBizInfo(Object[] args, Object jsonResult, Log controllerLog) {
        BizLogInfo bizInfo = new BizLogInfo();

        // 从方法参数中提取信息
        extractFromArgs(args, bizInfo,controllerLog);

        // 从返回结果中提取信息（通常包含新生成的ID）
        extractFromResult(jsonResult, bizInfo);

        // 根据注解信息推断业务类型
        String businessType = inferBusinessType(controllerLog);
        bizInfo.setBusinessType(businessType);

        return bizInfo;
    }

    /**
     * 从方法参数中提取业务信息
     */
    private void extractFromArgs(Object[] args, BizLogInfo bizInfo,Log controllerLog) {
        if (ArrayUtil.isEmpty(args)) {
            return;
        }
        // 获取配置的字段名
        String idField = controllerLog.idField();
        String nameField = controllerLog.nameField();

        for (Object arg : args) {
            if (ObjectUtil.isNull(arg)) {
                continue;
            }

            // 特殊处理：文件上传
            if (arg instanceof MultipartFile) {
                MultipartFile file = (MultipartFile) arg;
                if (bizInfo.getName() == null && StringUtils.isNotBlank(file.getOriginalFilename())) {
                    bizInfo.setName(file.getOriginalFilename());
                    bizInfo.setFileSize(formatFileSize(file.getSize()));
                }
                continue;
            }

            // 特殊处理：文件数组上传
            if (arg instanceof MultipartFile[]) {
                MultipartFile[] files = (MultipartFile[]) arg;
                if (files.length > 0 && bizInfo.getName() == null) {
                    if (files.length == 1) {
                        bizInfo.setName(files[0].getOriginalFilename());
                        bizInfo.setFileSize(formatFileSize(files[0].getSize()));
                    } else {
                        bizInfo.setName(files.length + "个文件");
                        long totalSize = Arrays.stream(files).mapToLong(MultipartFile::getSize).sum();
                        bizInfo.setFileSize(formatFileSize(totalSize));
                    }
                }
                continue;
            }


            if (isFilterObject(arg)) {
                continue;
            }

            Map<String, Object> paramMap = parseParamToMap(arg);
            if (MapUtil.isEmpty(paramMap)) {
                continue;
            }

            // 优先使用注解配置的字段名
            if (bizInfo.getId() == null) {
                String id = extractValue(paramMap, idField);
                if (id == null) {
                    // 如果指定字段没有值，使用通用字段名
                    id = extractValue(paramMap, "id", "userId", "projectId", "taskId","feedbackNo");
                }
                bizInfo.setId(id);
            }

            if (bizInfo.getName() == null) {
                String name = extractValue(paramMap, nameField);
                if (name == null) {
                    // 如果指定字段没有值，使用通用字段名
                    name = extractValue(paramMap, "name", "username", "deptName","roleName",
                        "menuName","projectName","drawName","feedbackNo",
                        "taskName", "orderName", "title", "fileName", "originalName");
                }
                bizInfo.setName(name);
            }

            // 新增：提取状态信息
            if (bizInfo.getStatus() == null) {
                String status = extractValue(paramMap, "status", "state", "statusCode");
                bizInfo.setStatus(status);
            }

            // 新增：提取其他可能有用的字段
            if (bizInfo.getCode() == null) {
                String code = extractValue(paramMap, "code", "projectCode", "taskCode");
                bizInfo.setCode(code);
            }
        }
    }
    /**
     * 从返回结果中提取业务信息（特别是新生成的ID）
     */
    private void extractFromResult(Object jsonResult, BizLogInfo bizInfo) {
        if (ObjectUtil.isNull(jsonResult)) {
            return;
        }

        try {
            // 假设返回结果是标准的R<T>结构
            Map<String, Object> resultMap = parseParamToMap(jsonResult);
            if (MapUtil.isEmpty(resultMap)) {
                return;
            }

            // 从data字段中提取ID（通常新增操作会返回新生成的ID）
            Object data = resultMap.get("data");
            if (data != null) {
                if (data instanceof Number) {
                    // 直接返回ID
                    bizInfo.setId(data.toString());
                } else if (data instanceof Map) {
                    // 从对象中提取ID
                    Map<String, Object> dataMap = (Map<String, Object>) data;
                    extractFromMap(dataMap, bizInfo);
                }
                else {
                    extractFromObject(data, bizInfo);
                }
            }
        } catch (Exception e) {
            log.warn("从返回结果提取业务信息失败: {}", e.getMessage());
        }
    }

    private void extractFromMap(Map<String, Object> dataMap, BizLogInfo bizInfo) {
        if (bizInfo.getId() == null) {
            // 采购订单ID相关字段（根据实际实体类字段调整）
            bizInfo.setId(extractValue(dataMap, "id", "childOrderId", "purchaseOrderId"));
        }
        if (bizInfo.getName() == null) {
            // 采购订单名称相关字段
            bizInfo.setName(extractValue(dataMap, "name", "orderName", "purchaseName","drawName",
                "supplierName", "menuName","projectName","drawName",
                "taskName", "title", "fileName", "originalName"));
        }
        if (bizInfo.getCode() == null) {
            // 采购订单编号相关字段
            bizInfo.setCode(extractValue(dataMap, "code", "orderCode", "purchaseCode", "no","drawCode"));
        }
    }

    /**
     * 把 String 当 JSON 解析成 Map（零依赖）
     */
    private Map<String, Object> parseStringToMap(String json) {
        // 格式：任意类名(键:值, 键:值, ...)
        Matcher m = Pattern.compile("^(\\w+)\\((.+)\\)$").matcher(json);
        if (!m.matches()) return Collections.emptyMap();

        String body = m.group(2);          // 括号内内容
        Map<String, Object> map = new LinkedHashMap<>();

        // 按逗号分割，但忽略括号内的逗号
        String[] pairs = body.split(", (?![^()]*\\))");
        for (String pair : pairs) {
            String[] kv = pair.split(":", 2);
            if (kv.length == 2) {
                map.put(kv[0].trim(), kv[1].trim());
            }
        }
        return map;
    }

    /**
     * 通过反射从任意实体对象中提取 id/name/code
     * 零依赖，不 import 任何 system 包
     */
    private void extractFromObject(Object data, BizLogInfo bizInfo) {
        if (data == null) return;
        // 跳过 JDK 核心类
        if (data instanceof String) {
            String s = ((String) data).replaceAll("=", ":");
            Map<String, Object> map = parseStringToMap(s);
            extractFromMap(map, bizInfo);
            return;
        }
        // 常见字段名池
        String[] idFields   = {"id", "childOrderId", "purchaseOrderId"};
        String[] nameFields = {"name", "orderName", "purchaseName", "supplierName"};
        String[] codeFields = {"code", "orderCode", "purchaseCode", "no"};

        // 反射所有字段（包括 private）
        Field[] fields = data.getClass().getDeclaredFields();
        for (Field field : fields) {
            if (Modifier.isStatic(field.getModifiers()) || field.isSynthetic()) continue;
            try {
                field.setAccessible(true);
                Object val = field.get(data);
                if (val == null) continue;

                String fieldName = field.getName();
                String strVal    = val.toString();

                // 只拿空字段，避免覆盖
                if (bizInfo.getId() == null   && Arrays.asList(idFields).contains(fieldName))   bizInfo.setId(strVal);
                if (bizInfo.getName() == null && Arrays.asList(nameFields).contains(fieldName)) bizInfo.setName(strVal);
                if (bizInfo.getCode() == null && Arrays.asList(codeFields).contains(fieldName)) bizInfo.setCode(strVal);

                // 只要拿到任意一个，就退出循环（减少反射次数）
                if (bizInfo.getName() != null || bizInfo.getCode() != null) return;

            } catch (IllegalAccessException e) {
                log.warn("反射获取字段失败: {}", field.getName());
            }
        }
    }

    /**
     * 推断业务类型
     */
    private String inferBusinessType(Log controllerLog) {
        String title = controllerLog.title().toLowerCase();
        String operDesc = controllerLog.operDesc().toLowerCase();
        String combined = title + " " + operDesc;

        // 根据标题和描述推断业务类型
        if (combined.contains("engineer") || combined.contains("工程师")) {
            return "engineer";
        } else if (combined.contains("project") || combined.contains("项目")) {
            return "project";
        } else if (combined.contains("task") || combined.contains("任务")) {
            return "task";
        } else if (combined.contains("approval") || combined.contains("审批")) {
            return "approval";
        } else if (combined.contains("user") || combined.contains("用户")) {
            return "user";
        } else if (combined.contains("role") || combined.contains("角色")) {
            return "role";
        } else if (combined.contains("drawing") || combined.contains("设计")) {
            return "drawing";
        } else if (combined.contains("oss") || combined.contains("上传") || combined.contains("upload")) {
            return "upload";
        } else if (combined.contains("product") || combined.contains("商品") || combined.contains("产品") || combined.contains("仓库")) {
            return "product";
        } else if (combined.contains("purchase") || combined.contains("采购") || combined.contains("订单")) {
            return "purchaseOrder";
        }

        return "default";
    }

    /**
     * 构建带超链接的业务描述
     */
    private String buildLinkedDescription(String baseDesc, BizLogInfo bizInfo, String result, Log controllerLog) {
        // 检查是否启用超链接
        if (!controllerLog.enableLink()) {
            if(baseDesc.equals("文件") || baseDesc.contains("上传")){
                String s = bizInfo.getDisplayName() + " ("+bizInfo.getFileSize()+")";
                return String.format("%s 【%s】 %s", baseDesc, s, result);
            }
            if (org.ehe.common.core.utils.StringUtils.isNotBlank(bizInfo.getStatus()) && !"0".equals(bizInfo.getStatus())) {
                return String.format("%s 【%s】状态【%s】 %s", baseDesc, bizInfo.getDisplayName(),bizInfo.getStatus(), result);
            }
            return String.format("%s 【%s】 %s", baseDesc, bizInfo.getDisplayName(), result);
        }

        // 如果操作失败，不添加链接
        if ("失败".equals(result)) {
            return String.format("%s 【%s】 %s", baseDesc, bizInfo.getDisplayName(), result);
        }

        // 如果没有ID或业务类型，返回普通描述
        if (bizInfo.getId() == null || !BUSINESS_URL_MAPPING.containsKey(bizInfo.getBusinessType())) {
            return buildSimpleDescription(baseDesc, bizInfo, result);
        }

        // 特殊处理文件上传
        if ("upload".equals(bizInfo.getBusinessType()) || controllerLog.linkType().equals("upload")) {
            return buildFileUploadDescription(baseDesc, bizInfo, result, controllerLog);
        }

        // 构建超链接
        String urlTemplate = BUSINESS_URL_MAPPING.get(bizInfo.getBusinessType());
        String detailUrl = urlTemplate.replace("{id}", bizInfo.getId());
        String linkedName = String.format("<a href='%s' target='_blank'>%s</a>", detailUrl, bizInfo.getDisplayName());

        if (StringUtils.isNotBlank(bizInfo.getStatus()) &&
            (baseDesc.contains("状态") || baseDesc.contains("status") || controllerLog.idField().equals("status"))) {

            // 提取业务对象类型（如"项目"、"任务"等）
            String bizMessage = null;
            if(org.ehe.common.core.utils.StringUtils.isNotBlank(bizInfo.getStatus())){
                bizMessage = String.format("%s:【%s】，状态【%s】， %s", controllerLog.title(), linkedName,
                    formatStatusDisplay(bizInfo.getStatus()), result);
            } else {
                bizMessage = String.format("%s:【%s】 %s", controllerLog.title(), linkedName, result);
            }
            return bizMessage;
        } else {
            return String.format("%s:【%s】 %s", controllerLog.title(), linkedName, result);
        }
    }

    /**
     * 构建简单描述（无链接）
     */
    private String buildSimpleDescription(String baseDesc, BizLogInfo bizInfo, String result) {
        String displayInfo = bizInfo.getDisplayName();
        if (StringUtils.isNotBlank(bizInfo.getFileSize())) {
            displayInfo = displayInfo + "(" + bizInfo.getFileSize() + ")";
        }
        return String.format("%s 【%s】 %s", baseDesc, displayInfo, result);
    }

    /**
     * 构建文件上传描述
     */
    private String buildFileUploadDescription(String baseDesc, BizLogInfo bizInfo, String result, Log controllerLog) {
        String fileName = bizInfo.getDisplayName();
        String fileInfo = fileName;

        if (StringUtils.isNotBlank(bizInfo.getFileSize())) {
            fileInfo = fileName + "(" + bizInfo.getFileSize() + ")";
        }

        // 如果有ID且启用链接，构建下载链接
        if (StringUtils.isNotBlank(bizInfo.getId()) && controllerLog.enableLink()) {
            String downloadUrl = "/system/oss/download/" + bizInfo.getId();
            String linkedFileName = String.format("<a href='%s' target='_blank'>%s</a>", downloadUrl, fileInfo);
            return String.format("%s:【%s】 %s", baseDesc, linkedFileName, result);
        } else {
            return String.format("%s:【%s】 %s", baseDesc, fileInfo, result);
        }
    }

    /**
     * 格式化文件大小
     */
    private String formatFileSize(long size) {
        if (size <= 0) return "0B";

        final String[] units = new String[]{"B", "KB", "MB", "GB", "TB"};
        int digitGroups = (int) (Math.log10(size) / Math.log10(1024));
        return String.format("%.1f%s", size / Math.pow(1024, digitGroups), units[digitGroups]);
    }

    /**
     * 从Map中提取指定key的值
     */
    private String extractValue(Map<String, Object> map, String... keys) {
        for (String keyword : keys) {
            if (map == null || map.isEmpty() || keyword == null) {
                return null;
            }
            // 遍历Map的所有键，判断是否包含关键字（不区分大小写）
            for (String key : map.keySet()) {
                if (key != null && key.toLowerCase().contains(keyword.toLowerCase())) {
                    Object value = map.get(key);
                    if (value != null) {
                        return value.toString();
                    }
                }
            }
        }

        return null;
    }

    /**
     * 将参数对象解析为Map
     */
    private Map<String, Object> parseParamToMap(Object param) {
        if (param instanceof Map) {
            return (Map<String, Object>) param;
        } else if (param instanceof String && JSONUtil.isJson(param.toString())) {
            return JsonUtils.parseMap(param.toString());
        } else {
            return BeanUtil.beanToMap(param, new HashMap<>(),
                CopyOptions.create()
                    .setIgnoreNullValue(true)
                    .setFieldValueEditor((fieldName, fieldValue) ->
                        fieldValue != null ? fieldValue.toString() : null));
        }
    }
    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param log     日志
     * @param operLog 操作日志
     * @throws Exception
     */
    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, OperLogEvent operLog, Object jsonResult) throws Exception {
        // 设置action动作
        operLog.setBusinessType(log.businessType().ordinal());
        // 设置标题
        operLog.setTitle(log.title());
        // 设置操作人类别
        operLog.setOperatorType(log.operatorType().ordinal());
        // 是否需要保存request，参数和值
        if (log.isSaveRequestData()) {
            // 获取参数的信息，传入到数据库中。
            setRequestValue(joinPoint, operLog, log.excludeParamNames());
        }
        // 是否需要保存response，参数和值
        if (log.isSaveResponseData() && ObjectUtil.isNotNull(jsonResult)) {
            operLog.setJsonResult(StringUtils.substring(JsonUtils.toJsonString(jsonResult), 0, 3800));
        }
    }

    /**
     * 获取请求的参数，放到log中
     *
     * @param operLog 操作日志
     * @throws Exception 异常
     */
    private void setRequestValue(JoinPoint joinPoint, OperLogEvent operLog, String[] excludeParamNames) throws Exception {
        Map<String, String> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
        String requestMethod = operLog.getRequestMethod();
        if (MapUtil.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name())) {
            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
            operLog.setOperParam(StringUtils.substring(params, 0, 3800));
        } else {
            MapUtil.removeAny(paramsMap, EXCLUDE_PROPERTIES);
            MapUtil.removeAny(paramsMap, excludeParamNames);
            operLog.setOperParam(StringUtils.substring(JsonUtils.toJsonString(paramsMap), 0, 3800));
        }
    }

    /**
     * 参数拼装
     */
    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames) {
        StringJoiner params = new StringJoiner(" ");
        if (ArrayUtil.isEmpty(paramsArray)) {
            return params.toString();
        }
        for (Object o : paramsArray) {
            if (ObjectUtil.isNotNull(o) && !isFilterObject(o)) {
                String str = JsonUtils.toJsonString(o);
                Dict dict = JsonUtils.parseMap(str);
                if (MapUtil.isNotEmpty(dict)) {
                    MapUtil.removeAny(dict, EXCLUDE_PROPERTIES);
                    MapUtil.removeAny(dict, excludeParamNames);
                    str = JsonUtils.toJsonString(dict);
                }
                params.add(str);
            }
        }
        return params.toString();
    }

    /**
     * 判断是否需要过滤的对象。
     *
     * @param o 对象信息。
     * @return 如果是需要过滤的对象，则返回true；否则返回false。
     */
    @SuppressWarnings("rawtypes")
    public boolean isFilterObject(final Object o) {
        Class<?> clazz = o.getClass();
        if (clazz.isArray()) {
            return MultipartFile.class.isAssignableFrom(clazz.getComponentType());
        } else if (Collection.class.isAssignableFrom(clazz)) {
            Collection collection = (Collection) o;
            for (Object value : collection) {
                return value instanceof MultipartFile;
            }
        } else if (Map.class.isAssignableFrom(clazz)) {
            Map map = (Map) o;
            for (Object value : map.values()) {
                return value instanceof MultipartFile;
            }
        }
        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
               || o instanceof BindingResult;
    }

    /**
     * 格式化状态显示
     */
    private String formatStatusDisplay(String status) {
        if (StringUtils.isBlank(status)) {
            return "未知状态";
        }

        // 可以根据实际业务需要添加状态映射
        Map<String, String> statusMapping = new HashMap<>();
        statusMapping.put("0", "待开始");
        statusMapping.put("1", "进行中");
        statusMapping.put("2", "已完成");
        statusMapping.put("3", "已暂停");
        statusMapping.put("4", "已取消");
        statusMapping.put("PENDING", "待处理");
        statusMapping.put("IN_PROGRESS", "进行中");
        statusMapping.put("COMPLETED", "已完成");
        statusMapping.put("CANCELLED", "已取消");

        return statusMapping.getOrDefault(status, status);
    }

    /**
     * 业务日志信息类
     */
    private static class BizLogInfo {
        private String id;
        private String name;
        private String code;
        private String businessType;

        private String linkType;

        private String status;

        private String createBy;

        private String fileSize;

        public String getId() {
            return id;
        }

        public void setId(String id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public String getBusinessType() {
            return businessType;
        }

        public void setBusinessType(String businessType) {
            this.businessType = businessType;
        }

        public String getLinkType() {
            return linkType;
        }

        public void setLinkType(String linkType) {
            this.linkType = linkType;
        }

        public String getStatus() {
            return status;
        }

        public void setStatus(String status) {
            this.status = status;
        }

        public String getCreateBy() {
            return createBy;
        }

        public void setCreateBy(String createBy) {
            this.createBy = createBy;
        }

        public String getFileSize() {
            return fileSize;
        }

        public void setFileSize(String fileSize) {
            this.fileSize = fileSize;
        }

        /**
         * 获取显示名称（优先显示name，其次code，最后id）
         */
        public String getDisplayName() {
            if (StringUtils.isNotBlank(name)) {
                return name;
            } else if (StringUtils.isNotBlank(code)) {
                return code;
            } else if (StringUtils.isNotBlank(id)) {
                return id;
            }
            return "未知";
        }
    }
}
